#ifndef SHARE_SEND_PROCESS_H
#define SHARE_SEND_PROCESS_H

#include <vector>
#include <string>
#include <functional>
#include <filesystem>

#include "FuseServer.h"
#include "Share.h"

#define BMP_FILE_SIGNATURE        0x4d42 // "BM"

#pragma pack (push, 1)
typedef struct {
    WORD signature;
    DWORD size;
    WORD res1;
    WORD res2;
    DWORD dataOffset;
} BmpHeader;
#pragma pack(pop)

class ShareSendProcess {
public:
    ShareSendProcess() { };
    virtual ~ShareSendProcess() { };
    virtual BOOL Init() = 0;
    virtual BOOL NextData(PBYTE *dataChunk, DWORD *chunkSize) = 0;
    virtual SIZE_T DataLen() = 0;
    virtual DWORD GetFormat() = 0;
    virtual PBYTE ExtraHeader() = 0;
    virtual DWORD ExtraHeaderLen() = 0;
};

class ClipboardShareSendTextProcess : public ShareSendProcess {
public:
    ClipboardShareSendTextProcess(
        std::function<std::string(FileShareList&)> updateWorker,
        std::function<void(const char*, DWORD)> sendShareName,
        DWORD format)
        : ShareSendProcess(),
          m_updateWorker(updateWorker),
          m_sendShareName(sendShareName),
          m_format(format),
          m_lpUnicode(nullptr),
          m_lpUnicodeData(nullptr),
          m_lpHtml(nullptr),
          m_lpHtmlData(nullptr),
          m_pos(0),
          m_header({0}) { };
    ~ClipboardShareSendTextProcess() override;
    BOOL Init() override;
    BOOL NextData(PBYTE *dataChunk, DWORD *chunkSize) override;
    SIZE_T DataLen() override;
    DWORD GetFormat() override;
    PBYTE ExtraHeader() override;
    DWORD ExtraHeaderLen() override;
private:
    DWORD m_format;
    HGLOBAL m_lpUnicode;
    PBYTE m_lpUnicodeData;
    HGLOBAL m_lpHtml;
    PBYTE m_lpHtmlData;
    SIZE_T m_pos;
    TextHeader m_header;
    std::vector<BYTE> m_utf8Data;
    std::function<std::string(FileShareList&)> m_updateWorker;
    std::function<void(const char*, DWORD)> m_sendShareName;
    BOOL GetHTMLData();
    BOOL CheckHTMLHeader();
    BOOL GetHTMLFiles();
    BOOL GetFileSize(const char *filePath, int64_t &fileSize);
};

class ClipboardShareSendBMPProcess : public ShareSendProcess {
public:
    ClipboardShareSendBMPProcess()
        : ShareSendProcess(),
          m_pos(0),
          m_size(0),
          m_hglb(nullptr),
          m_lpmem(nullptr),
          m_bmpHeader({0}) { };
    ~ClipboardShareSendBMPProcess() override;
    BOOL Init() override;
    BOOL NextData(PBYTE *dataChunk, DWORD *chunkSize) override;
    SIZE_T DataLen() override;
    DWORD GetFormat() override;
    PBYTE ExtraHeader() override;
    DWORD ExtraHeaderLen() override;

private:
    SIZE_T m_pos;
    SIZE_T m_size;
    HGLOBAL m_hglb;
    PBYTE m_lpmem;
    BmpHeader m_bmpHeader;
};

class ClipboardShareSendFilesProcess : public ShareSendProcess {
public:
    explicit ClipboardShareSendFilesProcess(
        std::function<std::string(FileShareList&)> updateWorker)
        : ShareSendProcess(),
          m_updateWorker(updateWorker),
          m_pos(0),
          m_size(0),
          m_hglb(nullptr),
          m_lpmem(nullptr) { };
    ~ClipboardShareSendFilesProcess() override;
    BOOL Init() override;
    BOOL NextData(PBYTE *dataChunk, DWORD *chunkSize) override;
    SIZE_T DataLen() override;
    DWORD GetFormat() override;
    PBYTE ExtraHeader() override;
    DWORD ExtraHeaderLen() override;

private:
    BOOL GetVolumeName(const std::wstring& wstr, std::string& fileName, std::string& filePath);
    BOOL GetFileName(const std::wstring& wstr, std::string& fileName, std::string& filePath);
    BOOL GetFileSystem(const std::wstring& wstr, BOOL& isHwFsFileSystem);
    BOOL AddClipboardVirtFolder(LPCWSTR mstr, SIZE_T len);
    BOOL IsPathExists(const std::filesystem::path& filename);
    SIZE_T m_pos;
    SIZE_T m_size;
    HGLOBAL m_hglb;
    PBYTE m_lpmem;
    std::vector<char> m_header;
    std::vector<char> m_data;
    std::function<std::string(FileShareList&)> m_updateWorker;
};

#endif // SHARE_SEND_PROCESS_H
